<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='global-property-S-'>/**
</span> * @fileOverview  UI控件的流程控制
 * @author yiminghe@gmail.com
 * copied by dxq613@gmail.com
 * @ignore
 */

var $ = require(&#39;jquery&#39;);

var Manager = require(&#39;../manage&#39;),

  UI_SET = &#39;_uiSet&#39;,
  ATTRS = &#39;ATTRS&#39;,
  ucfirst = BUI.ucfirst,
  noop = $.noop,
  Base = require(&#39;../../base&#39;);
<span id='global-method-initHierarchy'>/**
</span> * 模拟多继承
 * init attr using constructors ATTRS meta info
 * @ignore
 */
function initHierarchy(host, config) {
  callMethodByHierarchy(host, &#39;initializer&#39;, &#39;constructor&#39;);
}

function callMethodByHierarchy(host, mainMethod, extMethod) {
  var c = host.constructor,
    extChains = [],
    ext,
    main,
    exts,
    t;

  // define
  while (c) {

    // 收集扩展类
    t = [];
    if (exts = c.mixins) {
      for (var i = 0; i &lt; exts.length; i++) {
        ext = exts[i];
        if (ext) {
          if (extMethod != &#39;constructor&#39;) {
            //只调用真正自己构造器原型的定义，继承原型链上的不要管
            if (ext.prototype.hasOwnProperty(extMethod)) {
              ext = ext.prototype[extMethod];
            } else {
              ext = null;
            }
          }
          ext &amp;&amp; t.push(ext);
        }
      }
    }

    // 收集主类
    // 只调用真正自己构造器原型的定义，继承原型链上的不要管 !important
    // 所以不用自己在 renderUI 中调用 superclass.renderUI 了，UIBase 构造器自动搜寻
    // 以及 initializer 等同理
    if (c.prototype.hasOwnProperty(mainMethod) &amp;&amp; (main = c.prototype[mainMethod])) {
      t.push(main);
    }

    // 原地 reverse
    if (t.length) {
      extChains.push.apply(extChains, t.reverse());
    }

    c = c.superclass &amp;&amp; c.superclass.constructor;
  }

  // 初始化函数
  // 顺序：父类的所有扩展类函数 -&gt; 父类对应函数 -&gt; 子类的所有扩展函数 -&gt; 子类对应函数
  for (i = extChains.length - 1; i &gt;= 0; i--) {
    extChains[i] &amp;&amp; extChains[i].call(host);
  }
}

<span id='global-method-destroyHierarchy'>/**
</span> * 销毁组件顺序： 子类 destructor -&gt; 子类扩展 destructor -&gt; 父类 destructor -&gt; 父类扩展 destructor
 * @ignore
 */
function destroyHierarchy(host) {
  var c = host.constructor,
    extensions,
    d,
    i;

  while (c) {
    // 只触发该类真正的析构器，和父亲没关系，所以不要在子类析构器中调用 superclass
    if (c.prototype.hasOwnProperty(&#39;destructor&#39;)) {
      c.prototype.destructor.apply(host);
    }

    if ((extensions = c.mixins)) {
      for (i = extensions.length - 1; i &gt;= 0; i--) {
        d = extensions[i] &amp;&amp; extensions[i].prototype.__destructor;
        d &amp;&amp; d.apply(host);
      }
    }

    c = c.superclass &amp;&amp; c.superclass.constructor;
  }
}

<span id='global-method-constructPlugins'>/**
</span> * 构建 插件
 * @ignore
 */
function constructPlugins(plugins) {
  if (!plugins) {
    return;
  }
  BUI.each(plugins, function(plugin, i) {
    if (BUI.isFunction(plugin)) {
      plugins[i] = new plugin();
    }
  });
}

<span id='global-method-actionPlugins'>/**
</span> * 调用插件的方法
 * @ignore
 */
function actionPlugins(self, plugins, action) {
  if (!plugins) {
    return;
  }
  BUI.each(plugins, function(plugin, i) {
    if (plugin[action]) {
      plugin[action](self);
    }
  });
}

<span id='global-method-bindUI'>/**
</span> * 根据属性变化设置 UI
 * @ignore
 */
function bindUI(self) {
  /*var attrs = self.getAttrs(),
          attr,
          m;

      for (attr in attrs) {
          if (attrs.hasOwnProperty(attr)) {
              m = UI_SET + ucfirst(attr);
              if (self[m]) {
                  // 自动绑定事件到对应函数
                  (function (attr, m) {
                      self.on(&#39;after&#39; + ucfirst(attr) + &#39;Change&#39;, function (ev) {
                          // fix! 防止冒泡过来的
                          if (ev.target === self) {
                              self[m](ev.newVal, ev);
                          }
                      });
                  })(attr, m);
              }
          }
      }
      */
}

<span id='global-method-syncUI'>/**
</span> * 根据当前（初始化）状态来设置 UI
 * @ignore
 */
function syncUI(self) {
  var v,
    f,
    attrs = self.getAttrs();
  for (var a in attrs) {
    if (attrs.hasOwnProperty(a)) {
      var m = UI_SET + ucfirst(a);
      //存在方法，并且用户设置了初始值或者存在默认值，就同步状态
      if ((f = self[m])
        // 用户如果设置了显式不同步，就不同步，比如一些值从 html 中读取，不需要同步再次设置
        &amp;&amp; attrs[a].sync !== false &amp;&amp; (v = self.get(a)) !== undefined) {
        f.call(self, v);
      }
    }
  }
}

<span id='BUI-Component-UIBase'>/**
</span> * 控件库的基类，包括控件的生命周期,下面是基本的扩展类
 * &lt;p&gt;
 * &lt;img src=&quot;https://dxq613.github.io/assets/img/class-mixins.jpg&quot;/&gt;
 * &lt;/p&gt;
 * @class BUI.Component.UIBase
 * @extends BUI.Base
 * @param  {Object} config 配置项
 */
var UIBase = function(config) {

  var _self = this,
    id;

  // 读取用户设置的属性值并设置到自身
  Base.apply(_self, arguments);

  //保存用户传入的配置项
  _self.setInternal(&#39;userConfig&#39;, config);
  // 按照类层次执行初始函数，主类执行 initializer 函数，扩展类执行构造器函数
  initHierarchy(_self, config);

  var listener,
    n,
    plugins = _self.get(&#39;plugins&#39;)
    /*,
          listeners = _self.get(&#39;listeners&#39;)*/
  ;

  constructPlugins(plugins);

  var xclass = _self.get(&#39;xclass&#39;);
  if (xclass) {
    _self.__xclass = xclass; //debug 方便
  }
  actionPlugins(_self, plugins, &#39;initializer&#39;);

  // 是否自动渲染
  config &amp;&amp; config.autoRender &amp;&amp; _self.render();

};

UIBase.ATTRS = {


<span id='BUI-Component-UIBase-property-userConfig'>  /**
</span>   * 用户传入的配置项
   * @type {Object}
   * @readOnly
   * @protected
   */
  userConfig: {

  },
<span id='BUI-Component-UIBase-cfg-autoRender'>  /**
</span>   * 是否自动渲染,如果不自动渲染，需要用户调用 render()方法
   * &lt;pre&gt;&lt;code&gt;
   *  //默认状态下创建对象，并没有进行render
   *  var control = new Control();
   *  control.render(); //需要调用render方法
   *
   *  //设置autoRender后，不需要调用render方法
   *  var control = new Control({
   *   autoRender : true
   *  });
   * &lt;/code&gt;&lt;/pre&gt;
   * @cfg {Boolean} autoRender
   */
<span id='global-property-autoRender'>  /**
</span>   * 是否自动渲染,如果不自动渲染，需要用户调用 render()方法
   * @type {Boolean}
   * @ignore
   */
  autoRender: {
    value: false
  },
<span id='global-property-listeners'>  /**
</span>   * @type {Object}
   * 事件处理函数:
   *      {
   *        &#39;click&#39;:function(e){}
   *      }
   *  @ignore
   */
  listeners: {
    value: {}
  },
<span id='BUI-Component-UIBase-cfg-plugins'>  /**
</span>   * 插件集合
   * &lt;pre&gt;&lt;code&gt;
   *  var grid = new Grid({
   *    columns : [{},{}],
   *    plugins : [Grid.Plugins.RadioSelection]
   *  });
   * &lt;/code&gt;&lt;/pre&gt;
   * @cfg {Array} plugins
   */
<span id='BUI-Component-UIBase-property-plugins'>  /**
</span>   * 插件集合
   * @type {Array}
   * @readOnly
   */
  plugins: {
    //value : []
  },
<span id='BUI-Component-UIBase-property-rendered'>  /**
</span>   * 是否已经渲染完成
   * @type {Boolean}
   * @default  false
   * @readOnly
   */
  rendered: {
    value: false
  },
<span id='BUI-Component-UIBase-property-xclass'>  /**
</span>   * 获取控件的 xclass
   * @readOnly
   * @type {String}
   * @protected
   */
  xclass: {
    valueFn: function() {
      return Manager.getXClassByConstructor(this.constructor);
    }
  }
};

BUI.extend(UIBase, Base);

BUI.augment(UIBase, {
<span id='BUI-Component-UIBase-method-create'>  /**
</span>   * 创建DOM结构
   * @protected
   */
  create: function() {
    var self = this;
    // 是否生成过节点
    if (!self.get(&#39;created&#39;)) {
<span id='BUI-Component-UIBase-event-beforeCreateDom'>      /**
</span>       * @event beforeCreateDom
       * fired before root node is created
       * @param e
       */
      self.fire(&#39;beforeCreateDom&#39;);
      callMethodByHierarchy(self, &#39;createDom&#39;, &#39;__createDom&#39;);
      self._set(&#39;created&#39;, true);
<span id='BUI-Component-UIBase-event-afterCreateDom'>      /**
</span>       * @event afterCreateDom
       * fired when root node is created
       * @param e
       */
      self.fire(&#39;afterCreateDom&#39;);
      actionPlugins(self, self.get(&#39;plugins&#39;), &#39;createDom&#39;);
    }
    return self;
  },
<span id='BUI-Component-UIBase-method-render'>  /**
</span>   * 渲染
   */
  render: function() {
    var _self = this;
    // 是否已经渲染过
    if (!_self.get(&#39;rendered&#39;)) {
      var plugins = _self.get(&#39;plugins&#39;);
      _self.create(undefined);
      _self.set(&#39;created&#39;, true);
<span id='BUI-Component-UIBase-event-beforeRenderUI'>      /**
</span>       * @event beforeRenderUI
       * fired when root node is ready
       * @param e
       */
      _self.fire(&#39;beforeRenderUI&#39;);
      callMethodByHierarchy(_self, &#39;renderUI&#39;, &#39;__renderUI&#39;);

<span id='BUI-Component-UIBase-event-afterRenderUI'>      /**
</span>       * @event afterRenderUI
       * fired after root node is rendered into dom
       * @param e
       */

      _self.fire(&#39;afterRenderUI&#39;);
      actionPlugins(_self, plugins, &#39;renderUI&#39;);

<span id='BUI-Component-UIBase-event-beforeBindUI'>      /**
</span>       * @event beforeBindUI
       * fired before UIBase &#39;s internal event is bind.
       * @param e
       */

      _self.fire(&#39;beforeBindUI&#39;);
      bindUI(_self);
      callMethodByHierarchy(_self, &#39;bindUI&#39;, &#39;__bindUI&#39;);
      _self.set(&#39;binded&#39;, true);
<span id='BUI-Component-UIBase-event-afterBindUI'>      /**
</span>       * @event afterBindUI
       * fired when UIBase &#39;s internal event is bind.
       * @param e
       */

      _self.fire(&#39;afterBindUI&#39;);
      actionPlugins(_self, plugins, &#39;bindUI&#39;);

<span id='BUI-Component-UIBase-event-beforeSyncUI'>      /**
</span>       * @event beforeSyncUI
       * fired before UIBase &#39;s internal state is synchronized.
       * @param e
       */

      _self.fire(&#39;beforeSyncUI&#39;);

      syncUI(_self);
      callMethodByHierarchy(_self, &#39;syncUI&#39;, &#39;__syncUI&#39;);

<span id='BUI-Component-UIBase-event-afterSyncUI'>      /**
</span>       * @event afterSyncUI
       * fired after UIBase &#39;s internal state is synchronized.
       * @param e
       */

      _self.fire(&#39;afterSyncUI&#39;);
      actionPlugins(_self, plugins, &#39;syncUI&#39;);
      _self._set(&#39;rendered&#39;, true);
    }
    return _self;
  },
<span id='BUI-Component-UIBase-method-createDom'>  /**
</span>   * 子类可继承此方法，当DOM创建时调用
   * @protected
   * @method
   */
  createDom: noop,
<span id='BUI-Component-UIBase-method-renderUI'>  /**
</span>   * 子类可继承此方法，渲染UI时调用
   * @protected
   *  @method
   */
  renderUI: noop,
<span id='BUI-Component-UIBase-method-bindUI'>  /**
</span>   * 子类可继承此方法,绑定事件时调用
   * @protected
   * @method
   */
  bindUI: noop,
<span id='BUI-Component-UIBase-method-syncUI'>  /**
</span>   * 同步属性值到UI上
   * @protected
   * @method
   */
  syncUI: noop,

<span id='BUI-Component-UIBase-method-destroy'>  /**
</span>   * 析构函数
   */
  destroy: function() {
    var _self = this;
    if (_self.destroyed) { //防止返回销毁
      return _self;
    }
<span id='BUI-Component-UIBase-event-beforeDestroy'>    /**
</span>     * @event beforeDestroy
     * fired before UIBase &#39;s destroy.
     * @param e
     */
    _self.fire(&#39;beforeDestroy&#39;);

    actionPlugins(_self, _self.get(&#39;plugins&#39;), &#39;destructor&#39;);
    destroyHierarchy(_self);
<span id='BUI-Component-UIBase-event-afterDestroy'>    /**
</span>     * @event afterDestroy
     * fired before UIBase &#39;s destroy.
     * @param e
     */
    _self.fire(&#39;afterDestroy&#39;);
    _self.off();
    _self.clearAttrVals();
    _self.destroyed = true;
    return _self;
  }
});

//延时处理构造函数
function initConstuctor(c) {
  var constructors = [];
  while (c.base) {
    constructors.push(c);
    c = c.base;
  }
  for (var i = constructors.length - 1; i &gt;= 0; i--) {
    var C = constructors[i];
    //BUI.extend(C,C.base,C.px,C.sx);
    BUI.mix(C.prototype, C.px);
    BUI.mix(C, C.sx);
    C.base = null;
    C.px = null;
    C.sx = null;
  }
}

BUI.mix(UIBase, {
<span id='BUI-Component-UIBase-static-method-define'>  /**
</span>   * 定义一个类
   * @static
   * @param  {Function} base   基类构造函数
   * @param  {Array} extensions 扩展
   * @param  {Object} px  原型链上的扩展
   * @param  {Object} sx
   * @return {Function} 继承与基类的构造函数
   */
  define: function(base, extensions, px, sx) {
    if ($.isPlainObject(extensions)) {
      sx = px;
      px = extensions;
      extensions = [];
    }

    function C() {
      var c = this.constructor;
      if (c.base) {
        initConstuctor(c);
      }
      UIBase.apply(this, arguments);
    }

    BUI.extend(C, base); //无法延迟
    C.base = base;
    C.px = px; //延迟复制原型链上的函数
    C.sx = sx; //延迟复制静态属性

    //BUI.mixin(C,extensions);
    if (extensions.length) { //延迟执行mixin
      C.extensions = extensions;
    }

    return C;
  },
<span id='BUI-Component-UIBase-static-method-extend'>  /**
</span>   * 扩展一个类，基类就是类本身
   * @static
   * @param  {Array} extensions 扩展
   * @param  {Object} px  原型链上的扩展
   * @param  {Object} sx
   * @return {Function} 继承与基类的构造函数
   */
  extend: function extend(extensions, px, sx) {
    var args = $.makeArray(arguments),
      ret,
      last = args[args.length - 1];
    args.unshift(this);
    if (last.xclass) {
      args.pop();
      args.push(last.xclass);
    }
    ret = UIBase.define.apply(UIBase, args);
    if (last.xclass) {
      var priority = last.priority || (this.priority ? (this.priority + 1) : 1);

      Manager.setConstructorByXClass(last.xclass, {
        constructor: ret,
        priority: priority
      });
      //方便调试
      ret.__xclass = last.xclass;
      ret.priority = priority;
      ret.toString = function() {
        return last.xclass;
      }
    }
    ret.extend = extend;
    return ret;
  }
});

module.exports = UIBase;
</pre>
</body>
</html>
